package com.prj.ufdm.cloud.base.util;

import java.security.MessageDigest;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import com.prj.ufdm.cloud.base.util.BaseBase64Util; 

/**
 * 描述：AES 加解密工具类
 * 
 * java的默认jdk 不支持256位AES密钥,需要安装扩展包  http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
 * 下载之后得到 local_policy.jar ，US_export_policy.jar 两个jar包，把这两个jar包放到 jdk/lib/security 目录下，替换原来的两个jar包即可
 * @author 胡义振
 * @date 2018-12-07 
 */
public class BaseAesUtil {
	
    public static void main(String[] args) throws Exception {
	   
      String strMing = "1010101,1010301,1010302,1010303,1010304,1010401,1010402,1010601,1010602,1010701,1010901,1011001,1011101,1011102,1011301,2010204,2010502,2010506,3010101,3010102,3010103,3010104,3010201,3010301,3010401,3010402,3010501,3010701,3010901,3010902,3011002,3011003,3011101,3011201,3011401,3011501,3011601,3011701,4010202,4010301,4010302,4010304,5010301,5010601,5010602,5010605,5010606";
	  String strKey = "wxepgjjxiajunfng";
	  String strIvValue = "epsoftfundxiajfg";
	  String modeAndPadding = "AES/CBC/PKCS5Padding";
	  int aesType = 128;
	  String strKeyType = "0";
	  
      // 加密
      String strMi = encrypt(strMing, strKey, strIvValue, aesType, modeAndPadding, strKeyType, "utf-8");
      System.out.println("AES 加密："+ strMi);
      strMi = "IbNigEYlNKTn1B2USGyDA9BSqStSPG4dAhfspeXjEs4=";
      String strAesDecrypt =  decrypt(strMi, strKey, strIvValue, aesType, modeAndPadding, strKeyType, "GBK");
      System.out.println("AES 解密："+ strAesDecrypt);

   }

	/**
	 * 描述: 通过 AES 进行加密   
	 * @auther 胡义振
	 * @date 2018-12-07 
	 * @param strMing 明文
	 * @param strKey  密码
	 * @param strIvValue （只能是16位字符）
	 * @param aesType
	 *        128：16 位字符
	 *        256：32 位字符
	 * @param encodeType
	 * @param strKeyType 
	 *     0: 通过 SecretKeySpec 产生 （AES 加密 "密码"只能支持 16 位字符，24 位字符，32 位字符密码）
	 *     1: 通过 KeyGenerator  产生 （密码长度为任意长度）
	 * @return BASE64 密文
	 * @throws Exception
	 */
	public static String encrypt(String strMing,String strKey, String strIvValue, int aesType,String modeAndPadding,String strKeyType,String encoding) throws Exception{
		
		SecretKey secretKey = getSecreKey(strKeyType,strKey,aesType);
		SecretKeySpec keySpec = new SecretKeySpec(secretKey.getEncoded(), "AES");
		if(modeAndPadding==null || "".equals(modeAndPadding)) {
			modeAndPadding = "AES/CBC/PKCS5Padding";
		}
		Cipher cipher = Cipher.getInstance(modeAndPadding);
		if (null != strIvValue) {
			cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(strIvValue.getBytes()));
		} else {
			cipher.init(Cipher.ENCRYPT_MODE, keySpec);
		}
		if(encoding==null || "".equals(encoding)) {
			encoding = "utf-8";
		}
		byte[] encryptByte = cipher.doFinal(strMing.getBytes(encoding));
		String encryptStr = BaseBase64Util.encode(encryptByte);
		return encryptStr;
    }
	
	public static String decrypt(String base64Str, String strKey, String strIvValue, int aesType,String modeAndPadding,String strKeyType,String encoding) throws Exception{
		SecretKey secretKey = getSecreKey(strKeyType,strKey,aesType);
		SecretKeySpec keySpec = new SecretKeySpec(secretKey.getEncoded(), "AES");
		if(modeAndPadding==null || "".equals(modeAndPadding)) {
			modeAndPadding = "AES/CBC/PKCS5Padding";
		}
		Cipher cipher = Cipher.getInstance(modeAndPadding);
		if (null != strIvValue) {
			cipher.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(strIvValue.getBytes()));
		} else {
			cipher.init(Cipher.DECRYPT_MODE, keySpec);
		}
		byte[] decryptByte = cipher.doFinal(BaseBase64Util.decode(base64Str));
		if(encoding==null || "".equals(encoding)) {
			encoding = "utf-8";
		}
		String decryptStr = new String(decryptByte, encoding);
		return decryptStr;
    }
		
	/**
	 * 描述: 通过密码类型,与密码获取 SecretKey 对象 
	 * @auther 胡义振
	 * @date 2018-12-07 
	 * @param strKeyType 秘钥类型
	 *     0: 通过 SecretKeySpec 产生 （AES 加密 "秘钥"只能支持 16 位，24 位，32 位密码）
	 *     1: 通过 KeyGenerator  产生 
	 * @param strKey 秘钥 
	 * @param AESType 加密位数
	 * @return
	 */
	private static SecretKey getSecreKey(String strKeyType,String strKey,int aesType){
		SecretKey secretKey = null;
		try
		{
			// 为了能支持 PKCS7Padding 
//			Security.addProvider(new BouncyCastleProvider());
			if(strKeyType==null ||  "".equals(strKeyType)) {
				strKeyType = "0";
			}
			// 通过 SecretKeySpec 产生秘钥
			if("0".equals(strKeyType)){
				secretKey = new SecretKeySpec(strKey.getBytes(), "AES");
				
//				System.out.println("密钥的长度为：" + secretKey.getEncoded().length);
			}
			// 通过 keyGenerator 产生秘钥
			else if("1".equals(strKeyType)){
				if(aesType!=128 && aesType!=256) {
					aesType = 128;
				}
				KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
				SecureRandom secureRandom = null;
				if(aesType==128) {
					secureRandom = SecureRandom.getInstance("SHA1PRNG");
					secureRandom.setSeed(strKey.getBytes());
				}
				else if(aesType==256) {
	                MessageDigest digester=MessageDigest.getInstance("SHA-256");  
	                digester.update(strKey.getBytes());  
	                byte[] arrByteKey = digester.digest();
	                secureRandom = new SecureRandom(arrByteKey);
				}
				keyGenerator.init(aesType,secureRandom);
				secretKey = keyGenerator.generateKey();
			}
		}
		catch(Exception er){
			er.printStackTrace();
		}
		return secretKey;
	}
}